#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "NesInput.h"
#include "NesPPU.h"
#include "NesSystem.H"
#include "NesMapper.h"
#include "NesCPU6502.h"


static inline uint8_t ucNesCPUMemoryGet(uint16_t addr);
static inline void vNesCPUMemorySet(uint16_t addr, uint8_t value);
static inline uint16_t ucNesCPUMemoryWordGet(uint16_t addr);
static inline void vNesCPURegisterSet(uint8_t *reg, uint8_t value);
static inline uint8_t Pop(void);
static inline uint16_t PopWord(void);
static inline uint16_t GetInd(void);
static inline void vCPU_ADD(uint8_t value);
static inline void vCPU_CMP(uint8_t reg, uint8_t value);
static inline uint8_t vCPU_ASL(uint8_t value);
static inline uint8_t vCPU_LSR(uint8_t value);
static inline uint8_t vCPU_ROL(uint8_t value);
static inline uint8_t vCPU_ROR(uint8_t value);
static inline void vCPU_ASLAddr(void);
static inline void vCPU_LSRAddr(void);
static inline void vCPU_ROLAddr(void);
static inline void vCPU_RORAddr(void);
static inline void vCPU_JMP(uint16_t addr);
static inline void vCPU_BranchRelative(int8_t branch);


/* 2kByte */
uint8_t st_ucCPU_RAM[0x800];
/* 有些Mapper使用的拓展RAM 8kByte */
uint8_t st_ucCPU_SRAM[0x2000];

NesCPUInofType st_typeNesCPUInfo = {0};


/* CPU内存 */
int8_t cNesCPUBankAddr8kByteSet(int8_t cSerial, uint32_t uiAddr)
{
    uint8_t *pucAddr = g_typeNesInfo.PRG_ROM + (uiAddr % g_typeNesInfo.PRG_ROMSize);

    /* 分成4块，每块8kBtye */
    switch(cSerial)
    {
        case 0 : st_typeNesCPUInfo.ROMBank0 = pucAddr; break;
        case 1 : st_typeNesCPUInfo.ROMBank1 = pucAddr; break;
        case 2 : st_typeNesCPUInfo.ROMBank2 = pucAddr; break;
        case 3 : st_typeNesCPUInfo.ROMBank3 = pucAddr; break;

        default : return 1;
    }

    return 0;
}

int8_t cNesCPUBankAddr16kByteSet(int8_t cSerial, uint32_t uiAddr)
{
    uint8_t *pucAddr = g_typeNesInfo.PRG_ROM + (uiAddr % g_typeNesInfo.PRG_ROMSize);

    /* 分成2块，每块16kBtye */
    switch(cSerial)
    {
        case 0 : st_typeNesCPUInfo.ROMBank0 = pucAddr; st_typeNesCPUInfo.ROMBank1 = pucAddr + (1024 * 8); break;
        case 1 : st_typeNesCPUInfo.ROMBank2 = pucAddr; st_typeNesCPUInfo.ROMBank3 = pucAddr + (1024 * 8); break;

        default : return 1;
    }

    return 0;
}

int8_t cNesCPUBankAddr32kByteSet(uint32_t uiAddr)
{
    uint8_t *pucAddr = g_typeNesInfo.PRG_ROM + (uiAddr % g_typeNesInfo.PRG_ROMSize);

    st_typeNesCPUInfo.ROMBank0 = pucAddr;
    st_typeNesCPUInfo.ROMBank1 = pucAddr + (1024 * 8);
    st_typeNesCPUInfo.ROMBank2 = pucAddr + (1024 * 16);
    st_typeNesCPUInfo.ROMBank3 = pucAddr + (1024 * 24);

    return 0;
}

void vNesCPUMemoryLoad(uint16_t addr, uint32_t uiAddr, int32_t iLength)
{
    /* 加载程序代码前16kByte到CPU的第1个区域 */
    cNesCPUBankAddr16kByteSet(0, 0);
    /* 加载程序代码后16kByte到CPU的第2个区域 */
    cNesCPUBankAddr16kByteSet(1, g_typeNesInfo.PRG_ROMSize - (1024 * 16));
}

static inline uint8_t ucNesCPUMemoryGet(uint16_t addr)
{
    /* addr / 0x2000 : 8kByte */
    uint8_t ucValue, ucAddrBlock = addr >> 13;

    switch(ucAddrBlock)
    {
        /* 0x0000 - 0x1FFF: 4块空间，后面3块是前面1块的镜像 */
        case 0 : ucValue = st_typeNesCPUInfo.RAM[addr & 0x07FF]; break;

        /* 0x2000 - 0x3FFF */
        case 1 : ucValue = ucNesPPURegisterGet(addr); break;

        /* 0x4000 - 0x5FFF */
        case 2 :
            if(addr < 0x4018)
            {
                if(addr == 0x4016)
                    ucValue = ucNesInputBitGet(NES_JOYPAD1);
                else if(addr == 0x4017)
                    ucValue = ucNesInputBitGet(NES_JOYPAD2);
            }
            break;

        /* 0x6000 - 0x7FFF */
        case 3 : ucValue = st_typeNesCPUInfo.SRAM[addr & 0x1FFF]; break;

        /* 0x8000 - 0x9FFF */
        case 4 : ucValue = st_typeNesCPUInfo.ROMBank0[addr & 0x1FFF]; break;
        /* 0xA000 - 0xBFFF */
        case 5 : ucValue = st_typeNesCPUInfo.ROMBank1[addr & 0x1FFF]; break;
        /* 0xC000 - 0xDFFF */
        case 6 : ucValue = st_typeNesCPUInfo.ROMBank2[addr & 0x1FFF]; break;
        /* 0xE000 - 0xFFFF */
        case 7 : ucValue = st_typeNesCPUInfo.ROMBank3[addr & 0x1FFF]; break;

        default : ucValue = 0; break;
    }

    return ucValue;
}

static inline void vNesCPUMemorySet(uint16_t addr, uint8_t value)
{
    int16_t usAddr;
    /* addr / 0x2000 : 8kByte */
    uint8_t ucValue, ucAddrBlock = addr >> 13;

    switch(ucAddrBlock)
    {
        /* 0x0000 - 0x1FFF: 4块空间，后面3块是前面1块的镜像 */
        case 0 : st_typeNesCPUInfo.RAM[addr & 0x07FF] = value; break;

        /* 0x2000 - 0x3FFF */
        case 1 : vNesPPURegisterSet(addr, value); break;

        /* 0x4000 - 0x5FFF */
        case 2 :
            if(addr < 0x4018)
            {
                if(addr == 0x4014)
                {
                    /* 模拟DMA一次性传输256字节 */
                    usAddr = (uint16_t)value << 8;
                    vNesPPUOamRamSet(0, (usAddr < 0x2000) ? &st_typeNesCPUInfo.RAM[usAddr & 0x07FF] : &st_typeNesCPUInfo.SRAM[usAddr & 0x1FFF], 256);

                    /* 1次DMA传输需要513个时钟 */
                    st_typeNesCPUInfo.clockCnt += 513;
                    /* 奇数时钟需要额外再增加1个时钟 */
                    st_typeNesCPUInfo.clockCnt += st_typeNesCPUInfo.clockCnt & 1;
                }
                else if(addr == 0x4016)
                {
                    /* 复位输入 */
                    vNesInputReset(value);
                }
            }
            break;

        /* 0x6000 - 0x7FFF */
        case 3 : st_typeNesCPUInfo.SRAM[addr & 0x1FFF] = value;  break;

        /* Mapper 操作 */
        default : g_typeNesMapperInfo.vMapperSetFunction(addr, value); break;
    }
}

static inline uint16_t ucNesCPUMemoryWordGet(uint16_t addr)
{
    uint16_t lo, hi;

    lo = ucNesCPUMemoryGet(addr);
    hi = ucNesCPUMemoryGet(addr + 1);

    return lo | hi << 8;
}



/* 操作CPU寄存器 */
#define GetA()       st_typeNesCPUInfo.registers.A
#define SetA(value)  vNesCPURegisterSet(&st_typeNesCPUInfo.registers.A, (value))

#define GetY()       st_typeNesCPUInfo.registers.Y
#define SetY(value)  vNesCPURegisterSet(&st_typeNesCPUInfo.registers.Y, (value))

#define GetX()       st_typeNesCPUInfo.registers.X
#define SetX(value)  vNesCPURegisterSet(&st_typeNesCPUInfo.registers.X, (value))

#define GetPS()      st_typeNesCPUInfo.registers.PS
#define SetPS(value) (st_typeNesCPUInfo.registers.PS = (((value) & 0xEF) | Reserved))

#define GetPC()      st_typeNesCPUInfo.registers.PC
#define SetPC(value) (st_typeNesCPUInfo.registers.PC = (value))

#define GetSP()      st_typeNesCPUInfo.registers.SP
#define SetSP(value) (st_typeNesCPUInfo.registers.SP = (value))

#define SetFlags(flag)   (st_typeNesCPUInfo.registers.PS |= ((flag) | Reserved))
#define ClearFlags(flag) (st_typeNesCPUInfo.registers.PS &= ~(flag))
#define CheckFlag(flag) ((st_typeNesCPUInfo.registers.PS & (flag)) == (flag))


#define SetZeroNegativeFlags(value) \
do                                  \
{                                   \
    if((value) == 0)                \
    {                               \
        SetFlags(Zero);             \
    }                               \
    else if((value) & 0x80)         \
    {                               \
        SetFlags(Negative);         \
    }                               \
}while(0)

static inline void vNesCPURegisterSet(uint8_t *reg, uint8_t value)
{
    ClearFlags(Zero | Negative);

    SetZeroNegativeFlags(value);

    *reg = value;
}

#define GetOperand() (st_typeNesCPUInfo.operand)
#define GetOperandValue() ((st_typeNesCPUInfo.Mode >= vCPU_Zero) ? ucNesCPUMemoryGet(GetOperand()) : GetOperand())

#define Push(value)                                 \
do                                                  \
{                                                   \
    vNesCPUMemorySet(0x100 + (uint16_t)GetSP(), (value));  \
    SetSP(GetSP() - 1);                             \
}while(0)

#define PushWord(value)                                 \
do                                                      \
{                                                       \
    vNesCPUMemorySet(0x100 + (uint16_t)GetSP(), (value) >> 8); \
    SetSP(GetSP() - 1);                                 \
                                                        \
    vNesCPUMemorySet(0x100 + (uint16_t)GetSP(), (value));      \
    SetSP(GetSP() - 1);                                 \
}while(0)

static inline uint8_t Pop(void)
{
    SetSP(GetSP() + 1);
    return ucNesCPUMemoryGet(0x100 + (uint16_t)GetSP());
}

static inline uint16_t PopWord(void)
{
    uint8_t lo, hi;

    SetSP(GetSP() + 1);
    lo = ucNesCPUMemoryGet(0x100 + (uint16_t)GetSP());
    SetSP(GetSP() + 1);
    hi = ucNesCPUMemoryGet(0x100 + (uint16_t)GetSP());

    return ((uint16_t)hi << 8) | lo;
}

static inline uint16_t GetInd(void)
{
    uint16_t addr = GetOperand();

    if((addr & 0xFF) == 0xFF)
    {
        uint8_t lo = ucNesCPUMemoryGet(addr);
        uint8_t hi = ucNesCPUMemoryGet(addr - 0xFF);
        return (lo | ((uint16_t)hi) << 8);
    }

    return ucNesCPUMemoryWordGet(addr);
}


/* CPU指令 */
static inline void vCPU_ADD(uint8_t value)
{
    uint16_t result = (uint16_t)GetA() + (uint16_t)value + (CheckFlag(Carry) ? Carry : 0x00);

    ClearFlags(Carry | Negative | Overflow | Zero);
    SetZeroNegativeFlags((uint8_t)result);

    if(~(GetA() ^ value) & (GetA() ^ result) & 0x80)
        SetFlags(Overflow);

    if(result > 0xFF)
        SetFlags(Carry);

    SetA((uint8_t)result);
}

static inline void vCPU_CMP(uint8_t reg, uint8_t value)
{
    int8_t result = reg - value;

    ClearFlags(Carry | Negative | Zero);

    if(reg >= value)
        SetFlags(Carry);

    if(reg == value)
        SetFlags(Zero);

    if((result & 0x80) == 0x80)
        SetFlags(Negative);
}

static inline uint8_t vCPU_ASL(uint8_t value)
{
    uint8_t result = value << 1;

    ClearFlags(Carry | Negative | Zero);

    if(value & 0x80)
        SetFlags(Carry);

    SetZeroNegativeFlags(result);

    return result;
}

static inline uint8_t vCPU_LSR(uint8_t value)
{
    uint8_t result = value >> 1;

    ClearFlags(Carry | Negative | Zero);

    if(value & 0x01)
        SetFlags(Carry);

    SetZeroNegativeFlags(result);

    return result;
}

static inline uint8_t vCPU_ROL(uint8_t value)
{
    int8_t carryFlag = CheckFlag(Carry);
    uint8_t result = (value << 1 | (carryFlag ? 0x01 : 0x00));

    ClearFlags(Carry | Negative | Zero);

    if(value & 0x80)
        SetFlags(Carry);

    SetZeroNegativeFlags(result);

    return result;
}

static inline uint8_t vCPU_ROR(uint8_t value)
{
    int8_t carryFlag = CheckFlag(Carry);
    uint8_t result = (value >> 1 | (carryFlag ? 0x80 : 0x00));

    ClearFlags(Carry | Negative | Zero);

    if(value & 0x01)
        SetFlags(Carry);

    SetZeroNegativeFlags(result);

    return result;
}

static inline void vCPU_ASLAddr(void)
{
    uint16_t addr = GetOperand();
    uint8_t value = ucNesCPUMemoryGet(addr);
    // vNesCPUMemorySet(addr, value); //Dummy write
    vNesCPUMemorySet(addr, vCPU_ASL(value));
}

static inline void vCPU_LSRAddr(void)
{
    uint16_t addr = GetOperand();
    uint8_t value = ucNesCPUMemoryGet(addr);
    // vNesCPUMemorySet(addr, value); //Dummy write
    vNesCPUMemorySet(addr, vCPU_LSR(value));
}

static inline void vCPU_ROLAddr(void)
{
    uint16_t addr = GetOperand();
    uint8_t value = ucNesCPUMemoryGet(addr);
    // vNesCPUMemorySet(addr, value); //Dummy write
    vNesCPUMemorySet(addr, vCPU_ROL(value));
}

static inline void vCPU_RORAddr(void)
{
    uint16_t addr = GetOperand();
    uint8_t value = ucNesCPUMemoryGet(addr);
    // vNesCPUMemorySet(addr, value); //Dummy write
    vNesCPUMemorySet(addr, vCPU_ROR(value));
}

static inline void vCPU_JMP(uint16_t addr) { SetPC(addr); }

static inline void vCPU_BranchRelative(int8_t branch)
{
    int8_t offset = (int8_t)GetOperand();

    if(branch)
    {
        // /* 额外增加1个CPU时钟 */
        // st_typeNesCPUInfo.clockCnt += 1;

        /* 跨页也需要额外增加1个CPU时钟 */
        st_typeNesCPUInfo.clockCnt += ((GetOperand() ^ GetPC()) >> 8) & 1;

        SetPC(GetPC() + offset);
    }
}


//OP Codes
void vCPU_AND(void) { SetA(GetA() & GetOperandValue()); }
void vCPU_EOR(void) { SetA(GetA() ^ GetOperandValue()); }
void vCPU_ORA(void) { SetA(GetA() | GetOperandValue()); }
void vCPU_ADC(void) { vCPU_ADD(GetOperandValue()); }
void vCPU_SBC(void) { vCPU_ADD(GetOperandValue() ^ 0xFF); }
void vCPU_CPA(void) { vCPU_CMP(GetA(), GetOperandValue()); }
void vCPU_CPX(void) { vCPU_CMP(GetX(), GetOperandValue()); }
void vCPU_CPY(void) { vCPU_CMP(GetY(), GetOperandValue()); }

void vCPU_INC(void)
{
    uint16_t addr = GetOperand();
    ClearFlags(Negative | Zero);
    uint8_t value = ucNesCPUMemoryGet(addr);

    value++;
    SetZeroNegativeFlags(value);
    vNesCPUMemorySet(addr, value);
}

void vCPU_DEC(void)
{
    uint16_t addr = GetOperand();
    uint8_t value;

    ClearFlags(Negative | Zero);

    value = ucNesCPUMemoryGet(addr) - 1;

    SetZeroNegativeFlags(value);
    vNesCPUMemorySet(addr, value);
}

void vCPU_BIT(void)
{
    uint8_t value = GetOperandValue();

    ClearFlags(Zero | Overflow | Negative);

    if((GetA() & value) == 0)
        SetFlags(Zero);

    if(value & 0x40)
        SetFlags(Overflow);

    if(value & 0x80)
        SetFlags(Negative);
}

void vCPU_LDA(void) { SetA(GetOperandValue()); }
void vCPU_LDX(void) { SetX(GetOperandValue()); }
void vCPU_LDY(void) { SetY(GetOperandValue()); }
void vCPU_STA(void) { vNesCPUMemorySet(GetOperand(), GetA()); }
void vCPU_STX(void) { vNesCPUMemorySet(GetOperand(), GetX()); }
void vCPU_STY(void) { vNesCPUMemorySet(GetOperand(), GetY()); }
void vCPU_TAX(void) { SetX(GetA()); }
void vCPU_TAY(void) { SetY(GetA()); }
void vCPU_TSX(void) { SetX(GetSP()); }
void vCPU_TXA(void) { SetA(GetX()); }
void vCPU_TXS(void) { SetSP(GetX()); }
void vCPU_TYA(void) { SetA(GetY()); }
void vCPU_PHA(void) { Push(GetA()); }
void vCPU_PHP(void) { uint8_t flags = GetPS() | Break | Reserved; Push(flags); }
void vCPU_PLA(void) { SetA(Pop()); }
void vCPU_PLP(void) { SetPS(Pop()); }
void vCPU_INX(void) { SetX(GetX() + 1); }
void vCPU_INY(void) { SetY(GetY() + 1); }
void vCPU_DEX(void) { SetX(GetX() - 1); }
void vCPU_DEY(void) { SetY(GetY() - 1); }
void vCPU_ASL_Acc(void) { SetA(vCPU_ASL(GetA())); }
void vCPU_ASL_Memory(void) { vCPU_ASLAddr(); }
void vCPU_LSR_Acc(void) { SetA(vCPU_LSR(GetA())); }
void vCPU_LSR_Memory(void) { vCPU_LSRAddr(); }
void vCPU_ROL_Acc(void) { SetA(vCPU_ROL(GetA())); }
void vCPU_ROL_Memory(void) { vCPU_ROLAddr(); }
void vCPU_ROR_Acc(void) { SetA(vCPU_ROR(GetA())); }
void vCPU_ROR_Memory(void) { vCPU_RORAddr(); }
void vCPU_JMP_Abs(void) { vCPU_JMP(GetOperand()); }
void vCPU_JMP_Ind(void) { vCPU_JMP(GetInd()); }

void vCPU_JSR(void)
{
    uint16_t addr = GetOperand();

    PushWord((uint16_t)(GetPC() - 1));
    vCPU_JMP(addr);
}

void vCPU_RTS(void) { SetPC(PopWord() + 1); }
void vCPU_BCC(void) { vCPU_BranchRelative(!CheckFlag(Carry)); }
void vCPU_BCS(void) { vCPU_BranchRelative(CheckFlag(Carry)); }
void vCPU_BEQ(void) { vCPU_BranchRelative(CheckFlag(Zero)); }
void vCPU_BMI(void) { vCPU_BranchRelative(CheckFlag(Negative)); }
void vCPU_BNE(void) { vCPU_BranchRelative(!CheckFlag(Zero)); }
void vCPU_BPL(void) { vCPU_BranchRelative(!CheckFlag(Negative)); }
void vCPU_BVC(void) { vCPU_BranchRelative(!CheckFlag(Overflow)); }
void vCPU_BVS(void) { vCPU_BranchRelative(CheckFlag(Overflow)); }
void vCPU_CLC(void) { ClearFlags(Carry); }
void vCPU_CLD(void) { ClearFlags(Decimal); }
void vCPU_CLI(void) { ClearFlags(Interrupt); }
void vCPU_CLV(void) { ClearFlags(Overflow); }
void vCPU_SEC(void) { SetFlags(Carry); }
void vCPU_SED(void) { SetFlags(Decimal); }
void vCPU_SEI(void) { SetFlags(Interrupt); }

void vCPU_RTI(void) { SetPS(Pop()); SetPC(PopWord()); }

//Make sure the nop operation takes as many cycles as meant to
void vCPU_NOP(void) { GetOperandValue(); }

//Unofficial OpCodes
void vCPU_SLO(void)
{
    uint8_t value, shiftedValue;

    //ASL & ORA
    value = GetOperandValue();
    shiftedValue = vCPU_ASL(value);

    SetA(GetA() | shiftedValue);
    vNesCPUMemorySet(GetOperand(), shiftedValue);
}

void vCPU_SRE(void)
{
    uint8_t value, shiftedValue;

    //ROL & AND
    value = GetOperandValue();
    shiftedValue = vCPU_LSR(value);

    SetA(GetA() ^ shiftedValue);
    vNesCPUMemorySet(GetOperand(), shiftedValue);
}

void vCPU_RLA(void)
{
    uint8_t value, shiftedValue;

    //LSR & EOR
    value = GetOperandValue();
    shiftedValue = vCPU_ROL(value);

    SetA(GetA() & shiftedValue);
    vNesCPUMemorySet(GetOperand(), shiftedValue);
}

void vCPU_RRA(void)
{
    uint8_t value, shiftedValue;

    //ROR & ADC
    value = GetOperandValue(), shiftedValue = 0;
    shiftedValue = vCPU_ROR(value);

    vCPU_ADD(shiftedValue);
    vNesCPUMemorySet(GetOperand(), shiftedValue);
}

void vCPU_SAX(void) { vNesCPUMemorySet(GetOperand(), GetA() & GetX()); }

void vCPU_LAX(void)
{
    //LDA & LDX
    uint8_t value = GetOperandValue();

    SetX(value);
    SetA(value);
}

void vCPU_DCP(void)
{
    //DEC & CMP
    uint8_t value = GetOperandValue() - 1;

    vCPU_CMP(GetA(), value);
    vNesCPUMemorySet(GetOperand(), value);
}

void vCPU_ISB(void)
{
    //INC & SBC
    uint8_t value = GetOperandValue() + 1;

    vCPU_ADD(value ^ 0xFF);
    vNesCPUMemorySet(GetOperand(), value);
}

void vCPU_AAC(void)
{
    SetA(GetA() & GetOperandValue());

    ClearFlags(Carry);
    if(CheckFlag(Negative)) {
        SetFlags(Carry);
    }
}

void vCPU_ASR(void)
{
    ClearFlags(Carry);
    SetA(GetA() & GetOperandValue());
    if(GetA() & 0x01) {
        SetFlags(Carry);
    }
    SetA(GetA() >> 1);
}

void vCPU_ARR(void)
{
    SetA(((GetA() & GetOperandValue()) >> 1) | (CheckFlag(Carry) ? 0x80 : 0x00));
    ClearFlags(Carry | Overflow);
    if(GetA() & 0x40) {
        SetFlags(Carry);
    }
    if((CheckFlag(Carry) ? 0x01 : 0x00) ^ ((GetA() >> 5) & 0x01)) {
        SetFlags(Overflow);
    }
}

void vCPU_ATX(void)
{
    //LDA & TAX
    uint8_t value = GetOperandValue();

    SetA(value); //LDA
    SetX(GetA()); //TAX
    SetA(GetA()); //Update flags based on A
}

void vCPU_AXS(void)
{
    uint8_t opValue, value;

    //CMP & DEX
    opValue = GetOperandValue();
    value = (GetA() & GetX()) - opValue;

    ClearFlags(Carry);
    if((GetA() & GetX()) >= opValue) {
        SetFlags(Carry);
    }

    SetX(value);
}

void vCPU_SYA(void)
{
    uint8_t addrHigh, addrLow, value;

    addrHigh = GetOperand() >> 8;
    addrLow = GetOperand() & 0xFF;
    value = GetY() & (addrHigh + 1);

    //From here: http://forums.nesdev.com/viewtopic.php?f=3&t=3831&start=30
    //Unsure if this is accurate or not
    //"the target address for e.g. SYA becomes ((y & (addr_high + 1)) << 8) | addr_low instead of the normal ((addr_high + 1) << 8) | addr_low"
    // vNesCPUMemorySet(((uint16_t)(GetY() & (addrHigh + 1)) << 8) | addrLow, value);
    vNesCPUMemorySet((((uint16_t)(GetY() & (addrHigh + 1))) << 8) | addrLow, value);
}

void vCPU_SXA(void)
{
    uint8_t addrHigh, addrLow, value;

    addrHigh = GetOperand() >> 8;
    addrLow = GetOperand() & 0xFF;
    value = GetX() & (addrHigh + 1);

    vNesCPUMemorySet((((uint16_t)(GetX() & (addrHigh + 1))) << 8) | addrLow, value);
}

//Unimplemented/Incorrect Unofficial OP codes
void vCPU_HLT(void)
{
    //normally freezes the cpu, we can probably assume nothing will ever call this
    GetOperandValue();
}

void vCPU_UNK(void)
{
    //Make sure we take the right amount of cycles (not reliable for operations that write to memory, etc.)
    GetOperandValue();
}

void vCPU_AXA(void)
{
    uint16_t addr = GetOperand();

    //"This opcode stores the result of A AND X AND the high byte of the target address of the operand +1 in memory."
    //This may not be the actual behavior, but the read/write operations are needed for proper cycle counting
    vNesCPUMemorySet(GetOperand(), ((addr >> 8) + 1) & GetA() & GetX());
}

void vCPU_TAS(void)
{
    //"AND X register with accumulator and store result in stack
    //pointer, then AND stack pointer with the high byte of the
    //target address of the argument + 1. Store result in memory."
    uint16_t addr = GetOperand();
    SetSP(GetX() & GetA());
    vNesCPUMemorySet(addr, GetSP() & ((addr >> 8) + 1));
}

void vCPU_LAS(void)
{
    //"AND memory with stack pointer, transfer result to accumulator, X register and stack pointer."
    uint8_t value = GetOperandValue();
    SetA(value & GetSP());
    SetX(GetA());
    SetSP(GetA());
}

void vCPU_BRK(void)
{
    PushWord(GetPC() + 1);

    Push(GetPS() | Break | Reserved);
    SetFlags(Interrupt);

    if(st_typeNesCPUInfo.NMIFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(NMIVector));

        st_typeNesCPUInfo.NMIFlag = FALSE;
    }
    else if(st_typeNesCPUInfo.IRQFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(IRQVector));

        st_typeNesCPUInfo.IRQFlag = FALSE;
    }
    else if(st_typeNesCPUInfo.ResetFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(ResetVector));

        st_typeNesCPUInfo.ResetFlag = FALSE;
    }

    //Ensure we don't start an NMI right after running a BRK instruction (first instruction in IRQ handler must run first - needed for nmi_and_brk test)
    // st_typeNesCPUInfo.NMIFlag = FALSE;
}



void (*InstructionFunctionTable[256])(void) = {
    vCPU_BRK, vCPU_ORA,  vCPU_HLT,  vCPU_SLO,   vCPU_NOP,   vCPU_ORA,   vCPU_ASL_Memory, vCPU_SLO,   vCPU_PHP, vCPU_ORA,   vCPU_ASL_Acc, vCPU_AAC,   vCPU_NOP,     vCPU_ORA,   vCPU_ASL_Memory, vCPU_SLO,   //0
    vCPU_BPL, vCPU_ORA,  vCPU_HLT,  vCPU_SLO,   vCPU_NOP,   vCPU_ORA,   vCPU_ASL_Memory, vCPU_SLO,   vCPU_CLC, vCPU_ORA,   vCPU_NOP,     vCPU_SLO,   vCPU_NOP,     vCPU_ORA,   vCPU_ASL_Memory, vCPU_SLO,   //1
    vCPU_JSR, vCPU_AND,  vCPU_HLT,  vCPU_RLA,   vCPU_BIT,   vCPU_AND,   vCPU_ROL_Memory, vCPU_RLA,   vCPU_PLP, vCPU_AND,   vCPU_ROL_Acc, vCPU_AAC,   vCPU_BIT,     vCPU_AND,   vCPU_ROL_Memory, vCPU_RLA,   //2
    vCPU_BMI, vCPU_AND,  vCPU_HLT,  vCPU_RLA,   vCPU_NOP,   vCPU_AND,   vCPU_ROL_Memory, vCPU_RLA,   vCPU_SEC, vCPU_AND,   vCPU_NOP,     vCPU_RLA,   vCPU_NOP,     vCPU_AND,   vCPU_ROL_Memory, vCPU_RLA,   //3
    vCPU_RTI, vCPU_EOR,  vCPU_HLT,  vCPU_SRE,   vCPU_NOP,   vCPU_EOR,   vCPU_LSR_Memory, vCPU_SRE,   vCPU_PHA, vCPU_EOR,   vCPU_LSR_Acc, vCPU_ASR,   vCPU_JMP_Abs, vCPU_EOR,   vCPU_LSR_Memory, vCPU_SRE,   //4
    vCPU_BVC, vCPU_EOR,  vCPU_HLT,  vCPU_SRE,   vCPU_NOP,   vCPU_EOR,   vCPU_LSR_Memory, vCPU_SRE,   vCPU_CLI, vCPU_EOR,   vCPU_NOP,     vCPU_SRE,   vCPU_NOP,     vCPU_EOR,   vCPU_LSR_Memory, vCPU_SRE,   //5
    vCPU_RTS, vCPU_ADC,  vCPU_HLT,  vCPU_RRA,   vCPU_NOP,   vCPU_ADC,   vCPU_ROR_Memory, vCPU_RRA,   vCPU_PLA, vCPU_ADC,   vCPU_ROR_Acc, vCPU_ARR,   vCPU_JMP_Ind, vCPU_ADC,   vCPU_ROR_Memory, vCPU_RRA,   //6
    vCPU_BVS, vCPU_ADC,  vCPU_HLT,  vCPU_RRA,   vCPU_NOP,   vCPU_ADC,   vCPU_ROR_Memory, vCPU_RRA,   vCPU_SEI, vCPU_ADC,   vCPU_NOP,     vCPU_RRA,   vCPU_NOP,     vCPU_ADC,   vCPU_ROR_Memory, vCPU_RRA,   //7
    vCPU_NOP, vCPU_STA,  vCPU_NOP,  vCPU_SAX,   vCPU_STY,   vCPU_STA,   vCPU_STX,        vCPU_SAX,   vCPU_DEY, vCPU_NOP,   vCPU_TXA,     vCPU_UNK,   vCPU_STY,     vCPU_STA,   vCPU_STX,        vCPU_SAX,   //8
    vCPU_BCC, vCPU_STA,  vCPU_HLT,  vCPU_AXA,   vCPU_STY,   vCPU_STA,   vCPU_STX,        vCPU_SAX,   vCPU_TYA, vCPU_STA,   vCPU_TXS,     vCPU_TAS,   vCPU_SYA,     vCPU_STA,   vCPU_SXA,        vCPU_AXA,   //9
    vCPU_LDY, vCPU_LDA,  vCPU_LDX,  vCPU_LAX,   vCPU_LDY,   vCPU_LDA,   vCPU_LDX,        vCPU_LAX,   vCPU_TAY, vCPU_LDA,   vCPU_TAX,     vCPU_ATX,   vCPU_LDY,     vCPU_LDA,   vCPU_LDX,        vCPU_LAX,   //A
    vCPU_BCS, vCPU_LDA,  vCPU_HLT,  vCPU_LAX,   vCPU_LDY,   vCPU_LDA,   vCPU_LDX,        vCPU_LAX,   vCPU_CLV, vCPU_LDA,   vCPU_TSX,     vCPU_LAS,   vCPU_LDY,     vCPU_LDA,   vCPU_LDX,        vCPU_LAX,   //B
    vCPU_CPY, vCPU_CPA,  vCPU_NOP,  vCPU_DCP,   vCPU_CPY,   vCPU_CPA,   vCPU_DEC,        vCPU_DCP,   vCPU_INY, vCPU_CPA,   vCPU_DEX,     vCPU_AXS,   vCPU_CPY,     vCPU_CPA,   vCPU_DEC,        vCPU_DCP,   //C
    vCPU_BNE, vCPU_CPA,  vCPU_HLT,  vCPU_DCP,   vCPU_NOP,   vCPU_CPA,   vCPU_DEC,        vCPU_DCP,   vCPU_CLD, vCPU_CPA,   vCPU_NOP,     vCPU_DCP,   vCPU_NOP,     vCPU_CPA,   vCPU_DEC,        vCPU_DCP,   //D
    vCPU_CPX, vCPU_SBC,  vCPU_NOP,  vCPU_ISB,   vCPU_CPX,   vCPU_SBC,   vCPU_INC,        vCPU_ISB,   vCPU_INX, vCPU_SBC,   vCPU_NOP,     vCPU_SBC,   vCPU_CPX,     vCPU_SBC,   vCPU_INC,        vCPU_ISB,   //E
    vCPU_BEQ, vCPU_SBC,  vCPU_HLT,  vCPU_ISB,   vCPU_NOP,   vCPU_SBC,   vCPU_INC,        vCPU_ISB,   vCPU_SED, vCPU_SBC,   vCPU_NOP,     vCPU_ISB,   vCPU_NOP,     vCPU_SBC,   vCPU_INC,        vCPU_ISB    //F
};

const ModeEnum InstructionModeTable[256] = {
    vCPU_Imp, vCPU_IndX, vCPU_None, vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Acc,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //0
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //1
    vCPU_Abs, vCPU_IndX, vCPU_None, vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Acc,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //2
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //3
    vCPU_Imp, vCPU_IndX, vCPU_None, vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Acc,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //4
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //5
    vCPU_Imp, vCPU_IndX, vCPU_None, vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Acc,     vCPU_Imm,   vCPU_Ind,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //6
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //7
    vCPU_Imm, vCPU_IndX, vCPU_Imm,  vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Imp,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //8
    vCPU_Rel, vCPU_IndYW,vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroY,      vCPU_ZeroY, vCPU_Imp, vCPU_AbsYW, vCPU_Imp,     vCPU_AbsYW, vCPU_AbsXW,   vCPU_AbsXW, vCPU_AbsYW,      vCPU_AbsYW, //9
    vCPU_Imm, vCPU_IndX, vCPU_Imm,  vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Imp,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //A
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndY,  vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroY,      vCPU_ZeroY, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsY,  vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsY,       vCPU_AbsY,  //B
    vCPU_Imm, vCPU_IndX, vCPU_Imm,  vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Imp,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //C
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //D
    vCPU_Imm, vCPU_IndX, vCPU_Imm,  vCPU_IndX,  vCPU_Zero,  vCPU_Zero,  vCPU_Zero,       vCPU_Zero,  vCPU_Imp, vCPU_Imm,   vCPU_Imp,     vCPU_Imm,   vCPU_Abs,     vCPU_Abs,   vCPU_Abs,        vCPU_Abs,   //E
    vCPU_Rel, vCPU_IndY, vCPU_None, vCPU_IndYW, vCPU_ZeroX, vCPU_ZeroX, vCPU_ZeroX,      vCPU_ZeroX, vCPU_Imp, vCPU_AbsY,  vCPU_Imp,     vCPU_AbsYW, vCPU_AbsX,    vCPU_AbsX,  vCPU_AbsXW,      vCPU_AbsXW, //F
};

const int8_t CPUClockTable[256] = {
    7, 6, 2, 8,   3, 3, 5, 5,   3, 2, 2, 2,   4, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,
    6, 6, 2, 8,   3, 3, 5, 5,   4, 2, 2, 2,   4, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,

    6, 6, 2, 8,   3, 3, 5, 5,   3, 2, 2, 2,   3, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,
    6, 6, 2, 8,   3, 3, 5, 5,   4, 2, 2, 2,   5, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,

    2, 6, 2, 6,   3, 3, 3, 3,   2, 2, 2, 2,   4, 4, 4, 4,
    2, 6, 2, 6,   4, 4, 4, 4,   2, 5, 2, 5,   5, 5, 5, 5,
    2, 6, 2, 6,   3, 3, 3, 3,   2, 2, 2, 2,   4, 4, 4, 4,
    2, 5, 2, 5,   4, 4, 4, 4,   2, 4, 2, 4,   4, 4, 4, 4,

    2, 6, 2, 8,   3, 3, 5, 5,   2, 2, 2, 2,   4, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,
    2, 6, 3, 8,   3, 3, 5, 5,   2, 2, 2, 2,   4, 4, 6, 6,
    2, 5, 2, 8,   4, 4, 6, 6,   2, 4, 2, 7,   4, 4, 7, 7,
};



/* FetchOperand */
static inline uint16_t GetIndAddr(void)
{
    uint8_t lo, hi;

    lo = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);
    hi = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    return (((uint16_t)hi) << 8) | lo;
}

static inline uint8_t GetImmediate(void)
{
    uint8_t value = ucNesCPUMemoryGet(GetPC());

    SetPC(GetPC() + 1);

    return value;
}

static inline uint8_t GetZeroAddr(void)
{
    uint8_t value = ucNesCPUMemoryGet(GetPC());

    SetPC(GetPC() + 1);

    return value;
}

static inline uint8_t GetZeroXAddr(void)
{
    uint8_t value = ucNesCPUMemoryGet(GetPC());

    SetPC(GetPC() + 1);

    return value + GetX();
}

static inline uint8_t GetZeroYAddr(void)
{
    uint8_t value = ucNesCPUMemoryGet(GetPC());

    SetPC(GetPC() + 1);

    return value + GetY();
}

static inline uint16_t GetAbsAddr(void)
{
    uint8_t lo, hi;

    lo = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);
    hi = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    return (((uint16_t)hi) << 8) | lo;
}

static inline uint16_t GetAbsXAddr(void)
{
    uint16_t value;
    uint8_t lo, hi;

    lo = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);
    hi = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    value = (((uint16_t)hi) << 8) | lo;
    value += GetX();

    return value;
}

static inline uint16_t GetAbsYAddr(void)
{
    uint16_t value;
    uint8_t lo, hi;

    lo = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);
    hi = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    value = (((uint16_t)hi) << 8) | lo;
    value += GetY();

    return value;
}

static inline uint16_t GetIndXAddr(void)
{
    uint16_t addr;
    uint8_t zero;

    zero = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    zero += GetX();

    addr = (zero == 0xFF) ? (ucNesCPUMemoryGet(0xFF) | ((uint16_t)ucNesCPUMemoryGet(0x00)) << 8) : ucNesCPUMemoryWordGet(zero);

    return addr;
}

static inline uint16_t GetIndYAddr(void)
{
    uint16_t addr;
    uint8_t zero;

    zero = ucNesCPUMemoryGet(GetPC());
    SetPC(GetPC() + 1);

    addr = (zero == 0xFF) ? (ucNesCPUMemoryGet(0xFF) | ((uint16_t)ucNesCPUMemoryGet(0x00)) << 8) : ucNesCPUMemoryWordGet(zero);

    return addr + GetY();
}

static inline uint16_t FetchOperand(ModeEnum enumValue)
{
    switch(enumValue)
    {
        case vCPU_Acc:
        case vCPU_Imp:   return 0;
        case vCPU_Imm:
        case vCPU_Rel:   return GetImmediate();
        case vCPU_Zero:  return GetZeroAddr();
        case vCPU_ZeroX: return GetZeroXAddr();
        case vCPU_ZeroY: return GetZeroYAddr();
        case vCPU_Ind:   return GetIndAddr();
        case vCPU_IndX:  return GetIndXAddr();
        case vCPU_IndY:
        case vCPU_IndYW: return GetIndYAddr();
        case vCPU_Abs:   return GetAbsAddr();
        case vCPU_AbsX:
        case vCPU_AbsXW: return GetAbsXAddr();
        case vCPU_AbsY:
        case vCPU_AbsYW: return GetAbsYAddr();

        default: break;
    }

    return 0;
}


static inline void vNesCPUIrq(void)
{
    PushWord(GetPC());

    Push((GetPS() & ~Break) | Reserved);
    SetFlags(Interrupt);

    if(st_typeNesCPUInfo.NMIFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(NMIVector));

        st_typeNesCPUInfo.NMIFlag = FALSE;
    }
    else if(st_typeNesCPUInfo.IRQFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(IRQVector));

        st_typeNesCPUInfo.IRQFlag = FALSE;
    }
    else if(st_typeNesCPUInfo.ResetFlag == TRUE)
    {
        SetPC(ucNesCPUMemoryWordGet(ResetVector));

        st_typeNesCPUInfo.ResetFlag = FALSE;
    }

    /* 中断耗7个CPU时钟 */
    st_typeNesCPUInfo.clockCnt += 7;
}

void vNesCPUStart(void)
{
    //Use _memoryManager->Read() directly to prevent clocking the PPU/APU when setting PC at reset
    //st_typeNesCPUInfo.registers.PC = 0xC004;

    memset(&st_typeNesCPUInfo.registers, 0, sizeof(st_typeNesCPUInfo.registers));
    st_typeNesCPUInfo.registers.SP = 0xFF;
    st_typeNesCPUInfo.registers.PS = Reserved;
    st_typeNesCPUInfo.IRQFlag = FALSE;
    st_typeNesCPUInfo.NMIFlag = FALSE;
    st_typeNesCPUInfo.ResetFlag = TRUE;

    st_typeNesCPUInfo.clockCnt = 0;

    vNesCPUIrq();

    printf("A: 0x%02X  X: 0x%02X  Y: 0x%02X  PS: 0x%02X  SP: 0x%02X  PC: 0x%04X\r\n", st_typeNesCPUInfo.registers.A, st_typeNesCPUInfo.registers.X,\
                                                                                    st_typeNesCPUInfo.registers.Y, st_typeNesCPUInfo.registers.PS,\
                                                                                    st_typeNesCPUInfo.registers.SP, st_typeNesCPUInfo.registers.PC);
}

void vNesCPUInit(void)
{
    st_typeNesCPUInfo.RAM  = (uint8_t *)&st_ucCPU_RAM[0];
    st_typeNesCPUInfo.SRAM = (uint8_t *)&st_ucCPU_SRAM[0];
}

void vNesCPUExec(void)
{
    /* NTAR格式时，PPU的时钟为CPU的3倍 */
    while((g_typeNesInfo.ptypeCPUInfo->clockCnt * 3) < g_typeNesInfo.ptypePPUInfo->clockCnt)
    {
        /* 读取PC指向的指令 */
        st_typeNesCPUInfo.opCode = ucNesCPUMemoryGet(GetPC());

        SetPC(GetPC() + 1);

        /* 获取模式 */
        st_typeNesCPUInfo.Mode = InstructionModeTable[st_typeNesCPUInfo.opCode];
        /* 获取操作数 */
        st_typeNesCPUInfo.operand = FetchOperand(st_typeNesCPUInfo.Mode);
        /* 获取指令 */
        st_typeNesCPUInfo.Function = InstructionFunctionTable[st_typeNesCPUInfo.opCode];

//            printf("%04X, %02X, %02X, %04X\r\n", st_typeNesCPUInfo.registers.PC, st_typeNesCPUInfo.opCode, st_typeNesCPUInfo.Mode, st_typeNesCPUInfo.operand);
//            printf("A:%02X,X:%02X,Y:%02X,PS:%02X,SP:%02X\r\n\n",
//                st_typeNesCPUInfo.registers.A,
//                st_typeNesCPUInfo.registers.X,
//                st_typeNesCPUInfo.registers.Y,
//                st_typeNesCPUInfo.registers.PS,
//                st_typeNesCPUInfo.registers.SP);

        /* 执行指令 */
        st_typeNesCPUInfo.Function();

        /* 获取当前指令所耗CPU时钟 */
        st_typeNesCPUInfo.clockCnt += CPUClockTable[st_typeNesCPUInfo.opCode];

        /* 执行中断 */
        if(st_typeNesCPUInfo.IRQFlag || st_typeNesCPUInfo.NMIFlag)
        {
            vNesCPUIrq();
        }
    }
}

NesCPUInofType *ptyeNesCPUInfoGet(void)
{
    return &st_typeNesCPUInfo;
}
